package cn.nexd.location.indoor.core;

import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;

import java.util.List;

import cn.nexd.collector.NexdCollector;
import cn.nexd.collector.NexdCollectorAgent;
import cn.nexd.collector.NexdCollectorConfiguration;
import cn.nexd.collector.bean.BeaconScannerResult;
import cn.nexd.collector.bean.MixCollectorResult;
import cn.nexd.collector.bean.WifiCollectorResult;
import cn.nexd.collector.listener.BeaconCollectorListener;
import cn.nexd.collector.listener.MixCollectorListener;
import cn.nexd.collector.listener.WifiCollectorListener;
import cn.nexd.location.indoor.NexdIndoorLocation;
import cn.nexd.location.indoor.NexdIndoorLocationConfiguration;
import cn.nexd.location.indoor.bean.IndoorLocationDataStory;
import cn.nexd.location.indoor.listener.NexdIndoorLocationListener;
import cn.nexd.location.indoor.utils.AndroidUtil;

/**
 * Created by codngfish on 16/5/5.
 */
final class DefaultIndoorLocationSubjec implements IndoorLocationSubjec {
    private Context context;
    private NexdIndoorLocationConfiguration indoorLocationConfiguration;
    private NexdIndoorLocationListener indoorLocationListener;
    private long buildingId;
    private long floorId;
    private final NexdCollectorAgent collectorAgent;
    private final NexdCollectorConfiguration.Buidler buidler;
    private IndoorLocationDataStory indoorLocationDataStory;
    private IndoorLocationThread indoorLocationThread;

    public DefaultIndoorLocationSubjec(Context context) {
        this.context = context;
        collectorAgent = NexdCollectorAgent.getCollectorAgent(context);
        buidler = new NexdCollectorConfiguration.Buidler();
        indoorLocationDataStory = new IndoorLocationDataStory();

    }

    @Override
    public void setIndoorLocationConfiguration(NexdIndoorLocationConfiguration indoorLocationConfiguration) {
        this.indoorLocationConfiguration = indoorLocationConfiguration;
    }

    @Override
    public void setIndoorLocationListener(NexdIndoorLocationListener indoorLocationListener) {
        this.indoorLocationListener = indoorLocationListener;
    }

    @Override
    public void startLocation(long buildingId, long floorId) {
        this.buildingId = buildingId;
        this.floorId = floorId;
        start();
    }

    private void start() {
        if (TextUtils.isEmpty(indoorLocationConfiguration.locationConfigPath)) {
            NexdIndoorLocation.BASE_CONFIGURATION_PATH = AndroidUtil.getDiskCacheDir(context, "nexdLocation");
        } else {
            NexdIndoorLocation.BASE_CONFIGURATION_PATH = indoorLocationConfiguration.locationConfigPath;
        }
        //        Log.d("default_path", "" + NexdIndoorLocation.getConfigurationPath(10086));
        indoorLocationThread = new IndoorLocationThread(context);
        initLocationConfig();
        collectorAgent.startCollector();
    }

    private void initLocationConfig() {
        buidler.setAppkey(indoorLocationConfiguration.appKey);
        switch (indoorLocationConfiguration.locationMode) {
            case LOCATION_MODE_WIFI_ONLY:
                buidler.setWifiCollectorDelay(indoorLocationConfiguration.wifiCollectorRate / 5);
                buidler.setWifiCollectorRate(indoorLocationConfiguration.wifiCollectorRate);
                buidler.setWifiCollectorEnable(true);
                buidler.setBluetoothCollectorEnable(false);
                collectorAgent.setWifiCollectorListener(new DefaultWifiCollectorListener());
                collectorAgent.setBeaconCollectorListener(null);
                collectorAgent.setMixCollectorListener(null);
                break;
            case LOCATION_MODE_BEACON_ONLY:
                buidler.setBeaconCollectorDelay(indoorLocationConfiguration.beaconCollectorRate / 5);
                buidler.setBluetoothCollectorRate(indoorLocationConfiguration.beaconCollectorRate);
                buidler.setBluetoothCollectorEnable(true);
                buidler.setWifiCollectorEnable(false);
                collectorAgent.setWifiCollectorListener(null);
                collectorAgent.setBeaconCollectorListener(new DefaultBeaconCollectorListener());
                collectorAgent.setMixCollectorListener(null);
                break;
            case LOCATION_MODE_MIX:
                buidler.setWifiCollectorDelay(indoorLocationConfiguration.wifiCollectorRate / 5);
                buidler.setWifiCollectorRate(indoorLocationConfiguration.wifiCollectorRate);
                buidler.setBeaconCollectorDelay(indoorLocationConfiguration.beaconCollectorRate / 5);
                buidler.setBluetoothCollectorRate(indoorLocationConfiguration.beaconCollectorRate);
                buidler.setBluetoothCollectorEnable(true);
                buidler.setWifiCollectorEnable(true);
                collectorAgent.setWifiCollectorListener(null);
                collectorAgent.setBeaconCollectorListener(null);
                collectorAgent.setMixCollectorListener(new DefaultMixCollectorListener());
                break;
        }
        collectorAgent.setCollectorConfiguration(buidler.build());
    }

    @Override
    public void stopLocation() {
        collectorAgent.stopCollector();
    }

    @Override
    public void destroyLocation() {
        collectorAgent.destroyCollector();
        indoorLocationThread.free();
    }

    public class DefaultBeaconCollectorListener implements BeaconCollectorListener {
        @Override
        public void onCollectionStart() {
            indoorLocationListener.onLocationStart(buildingId, floorId, indoorLocationConfiguration.locationMode);
        }

        @Override
        public void onCollectionSuccess(List<BeaconScannerResult> collectorResults) {
            indoorLocationDataStory.addBeaconCollectorResults(collectorResults);
            if (indoorLocationThread.getCurrentIndoorLocationThreadState()) {
                // 中断
                ((Activity) context).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        destroyLocation();
                    }
                });
            } else {
                indoorLocationThread.start(buildingId, floorId, false, indoorLocationDataStory.getIndoorLocationDatas(), indoorLocationListener, indoorLocationConfiguration);

                //                runOnUiThread(new Runnable() {
//                    @Override
//                    public void run() {
//                        if (indoorLocationDataStory.getIndoorLocationDatas().size() == 0) {
//                            Log.d("location", "Beacon data size null");
//                        }
//                        indoorLocationThread.start(buildingId, floorId, false, indoorLocationDataStory.getIndoorLocationDatas(), indoorLocationListener, indoorLocationConfiguration);
//                    }
//                });
            }
        }

        @Override
        public void onCollectorFailed(NexdCollector.CollectorState collectorState) {
            indoorLocationListener.onLocationFailed(translate(collectorState));
        }

        @Override
        public void onCollectorInterrupt(NexdCollector.CollectorState collectorState) {
            indoorLocationListener.onLocationInterrupt(translate(collectorState));
        }
    }

    public class DefaultWifiCollectorListener implements WifiCollectorListener {
        @Override
        public void onCollectionStart() {
            indoorLocationListener.onLocationStart(buildingId, floorId, indoorLocationConfiguration.locationMode);
        }

        @Override
        public void onCollectionSuccess(List<WifiCollectorResult> collectorResults) {
            indoorLocationDataStory.addWifiCollectorResults(collectorResults);
            if (indoorLocationThread.getCurrentIndoorLocationThreadState()) {
                // 中断
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        destroyLocation();
                    }
                });
            } else {
                indoorLocationThread.start(buildingId, floorId, false, indoorLocationDataStory.getIndoorLocationDatas(), indoorLocationListener, indoorLocationConfiguration);

                //                runOnUiThread(new Runnable() {
//                    @Override
//                    public void run() {
//                        if (indoorLocationDataStory.getIndoorLocationDatas().size() == 0) {
//                            Log.d("location", "wifi data size null");
//                        }
//                        indoorLocationThread.start(buildingId, floorId, false, indoorLocationDataStory.getIndoorLocationDatas(), indoorLocationListener, indoorLocationConfiguration);
//                    }
//                });
            }
        }

        @Override
        public void onCollectorFailed(NexdCollector.CollectorState collectorState) {
            indoorLocationListener.onLocationFailed(translate(collectorState));

        }

        @Override
        public void onCollectorInterrupt(NexdCollector.CollectorState collectorState) {
            indoorLocationListener.onLocationInterrupt(translate(collectorState));
        }
    }

    public class DefaultMixCollectorListener implements MixCollectorListener {
        @Override
        public void onCollectionStart() {
            indoorLocationListener.onLocationStart(buildingId, floorId, indoorLocationConfiguration.locationMode);
        }

        @Override
        public void onCollectionSuccess(List<MixCollectorResult> collectorResults) {
            indoorLocationDataStory.addMixCollectorResults(collectorResults);
            if (indoorLocationThread.getCurrentIndoorLocationThreadState()) {
                // 中断
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        destroyLocation();
                    }
                });
            } else {
                indoorLocationThread.start(buildingId, floorId, false, indoorLocationDataStory.getIndoorLocationDatas(), indoorLocationListener, indoorLocationConfiguration);

                //                runOnUiThread(new Runnable() {
//                    @Override
//                    public void run() {
//                        if (indoorLocationDataStory.getIndoorLocationDatas().size() == 0) {
//                            Log.d("location", "mix data size null");
//                        }
//                        indoorLocationThread.start(buildingId, floorId, false, indoorLocationDataStory.getIndoorLocationDatas(), indoorLocationListener, indoorLocationConfiguration);
//                    }
//                });
            }
        }

        @Override
        public void onCollectorFailed(NexdCollector.CollectorState collectorState) {
            indoorLocationListener.onLocationFailed(translate(collectorState));

        }

        @Override
        public void onCollectorInterrupt(NexdCollector.CollectorState collectorState) {
            indoorLocationListener.onLocationInterrupt(translate(collectorState));
        }
    }

    private NexdIndoorLocation.LocationState translate(NexdCollector.CollectorState collectorState) {
        switch (collectorState) {
            case COLLECTOR_FAILED_TYPE_NO_BEACON_FOUND:
                return NexdIndoorLocation.LocationState.LOCATION_FAILED_TYPE_NO_BEACON_FOUND;
            case COLLECTOR_FAILED_TYPE_NO_WIFI_FOUND:
                return NexdIndoorLocation.LocationState.LOCATION_FAILED_TYPE_NO_WIFI_FOUND;
            case COLLECTOR_INTERRUPT_TYPE_CAN_NOT_ACCESS_DATA:
                return NexdIndoorLocation.LocationState.LOCATION_INTERRUPT_TYPE_CAN_NOT_ACCESS_DATA;
            case COLLECTOR_INTERRUPT_TYPE_COLLECTOR_STATE_UNAVAILABLE:
                return NexdIndoorLocation.LocationState.LOCATION_INTERRUPT_TYPE_COLLECTOR_STATE_UNAVAILABLE;
            case COLLECTOR_INTERRUPT_TYPE_NO_WIFI_BEACON_FOUND:
                return NexdIndoorLocation.LocationState.LOCATION_INTERRUPT_TYPE_NO_WIFI_BEACON_FOUND;
            case COLLECTOR_INTERRUPT_TYPE_PERMISSION_UNAVAILABLE:
                return NexdIndoorLocation.LocationState.LOCATION_INTERRUPT_TYPE_PERMISSION_UNAVAILABLE;
            case COLLECTOR_INTERRUPT_TYPE_COLLECTOR_UNAVAILABLE:
                return NexdIndoorLocation.LocationState.LOCATION_INTERRUPT_COLLECTOR_UNAVAILABLE;
        }
        return null;
    }

    private void runOnUiThread(Runnable runnable) {
        ((Activity) context).runOnUiThread(runnable);
    }
}
